package com.plian.system.service.zzd.helper;

import com.plian.Tools.*;
import com.plian.system.dto.zzd.ZZDQuery;
import com.plian.system.vo.fr.indicatorsValue.IndicatorsReportVO;
import com.plian.system.vo.fr.indicatorsValue.IndicatorsValueVO;
import com.plian.system.vo.zzd.finance.FinancialDataVO;
import org.springframework.lang.Nullable;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.plian.system.constant.fr.IndicatorsCodeConstant.*;
import static java.util.stream.Collectors.reducing;

public class ZZDHelper {

    /**
     * 搜索参数检查
     * @param zzdQuery
     */
    public static void checkQuery(ZZDQuery zzdQuery){
        if(StringUtil.isBlank(zzdQuery.getReportTime())){
            zzdQuery.setReportTime(DateUtil.format(DateUtil.now(), DateUtil.PATTERN_MONTH));
        }
    }

    /**
     * indicatorsValueVOS to codeMap (大通商处理) 年度大于2019的快报数据
     * @param year
     * @param indicatorsValueVOS
     * @param subtractChildList
     * @param addChildList
     * @param sumChildOrgIds
     * @return
     */
    public static Map<String, BigDecimal> indicatorsValueToValueMap(int year, List<IndicatorsValueVO> indicatorsValueVOS, List<String> subtractChildList,
                                                              List<String> addChildList, List<String> sumChildOrgIds){
        if (year <= 2019){
            return indicatorsValueVOS.stream()
                    .collect(Collectors.groupingBy(IndicatorsValueVO::getCode, reducing(BigDecimal.ZERO, IndicatorsValueVO::getValue, BigDecimal::add)));

        }
        Map<String, List<IndicatorsValueVO>> valueVOMap = indicatorsValueVOS.stream().collect(Collectors.groupingBy(IndicatorsValueVO::getCode));
        return valueVOMapToValueMap(valueVOMap, subtractChildList, addChildList, sumChildOrgIds);
    }

    /**
     * indicatorsValueVOS to codeMap (大通商处理) 年度大于2019的快报数据
     * @param year
     * @param indicatorsValueVOS
     * @param subtractChildList
     * @param addChildList
     * @param sumChildOrgIds
     * @return
     */
    public static Map<String, BigDecimal> indicatorsValueToMonthValueMap(int year, List<IndicatorsValueVO> indicatorsValueVOS, List<String> subtractChildList,
                                                                    List<String> addChildList, List<String> sumChildOrgIds){
        if (year <= 2019){
            return indicatorsValueVOS.stream()
                    .collect(Collectors.groupingBy(indicatorsValueVO -> indicatorsValueVO.getCode() + StringPool.DASH + Integer.valueOf(indicatorsValueVO.getMonth()),
                            reducing(BigDecimal.ZERO, IndicatorsValueVO::getValue, BigDecimal::add)));

        }
        Map<String, List<IndicatorsValueVO>> valueVOMap = indicatorsValueVOS.stream()
                .collect(Collectors.groupingBy(indicatorsValueVO -> indicatorsValueVO.getCode() + StringPool.DASH + Integer.valueOf(indicatorsValueVO.getMonth())));
        return valueVOMapToValueMap(valueVOMap, subtractChildList, addChildList, sumChildOrgIds);
    }

    /**
     * 大通商数据处理
     * @param valueVOMap
     * @param subtractChildList
     * @param addChildList
     * @param sumChildOrgIds
     * @return
     */
    public static Map<String, BigDecimal> valueVOMapToValueMap(Map<String, List<IndicatorsValueVO>> valueVOMap, List<String> subtractChildList,
                                                               List<String> addChildList, List<String> sumChildOrgIds){
        Map<String, BigDecimal> valueMap = new HashMap<>();
        valueVOMap.forEach((key , list) -> {
            BigDecimal sumValue = list.stream().filter(indicatorsValueVO -> sumChildOrgIds.contains(indicatorsValueVO.getOrgId()))
                    .map(IndicatorsValueVO::getValue).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (CollectionUtil.isNotEmpty(addChildList)){
                BigDecimal addValue = list.stream().filter(indicatorsValueVO -> addChildList.contains(indicatorsValueVO.getOrgId()))
                        .map(IndicatorsValueVO::getValue).reduce(BigDecimal.ZERO, BigDecimal::add);
                sumValue = BigDecimalUtil.add(sumValue, addValue);
            }
            if (CollectionUtil.isNotEmpty(subtractChildList)){
                BigDecimal subtractValue = list.stream().filter(indicatorsValueVO -> subtractChildList.contains(indicatorsValueVO.getOrgId()))
                        .map(IndicatorsValueVO::getValue).reduce(BigDecimal.ZERO, BigDecimal::add);
                sumValue = BigDecimalUtil.subtract(sumValue, subtractValue);
            }
            valueMap.put(key, sumValue);
        });
        return valueMap;
    }

    /**
     *
     * @param codeValueMap
     * @param unit 单位 默认万元
     * @return
     */
    public static  FinancialDataVO codeValueMapToDataVO(Map<String, BigDecimal> codeValueMap, @Nullable BigDecimal unit){
        return Optional.ofNullable(codeValueMap)
                .map(map -> {
                    FinancialDataVO dataVO = new FinancialDataVO();
                    dataVO.setTotalAssets(BigDecimalUtil.divide(map.getOrDefault(K22, BigDecimal.ZERO), unit, 2, BigDecimal.ROUND_HALF_UP));
                    dataVO.setTotalLiabilities(BigDecimalUtil.divide(map.getOrDefault(K30, BigDecimal.ZERO), unit, 2, BigDecimal.ROUND_HALF_UP));
                    dataVO.setTotalNetAssets(BigDecimalUtil.divide(map.getOrDefault(K36, BigDecimal.ZERO), unit, 2, BigDecimal.ROUND_HALF_UP));
                    dataVO.setBusinessIncome(BigDecimalUtil.divide(map.getOrDefault(KLJ1, BigDecimal.ZERO), unit, 2, BigDecimal.ROUND_HALF_UP));
                    dataVO.setTotalProfit(BigDecimalUtil.divide(map.getOrDefault(KLJ19, BigDecimal.ZERO), unit, 2, BigDecimal.ROUND_HALF_UP));
                    dataVO.setTotalLiabilitiesRatio(BigDecimalUtil.divide(map.getOrDefault(K30, BigDecimal.ZERO), map.getOrDefault(K22, BigDecimal.ZERO), 2, BigDecimal.ROUND_HALF_UP, 100));
                    dataVO.setRdInvestmentIntensity(BigDecimalUtil.divide(map.getOrDefault(KSUM62, BigDecimal.ZERO), map.getOrDefault(KLJ1, BigDecimal.ZERO), 2, BigDecimal.ROUND_HALF_UP, 100));
                    dataVO.setLaborGenerationRate(BigDecimalUtil.divide(map.getOrDefault(KSUM49, BigDecimal.ZERO), map.getOrDefault(KSUM59, BigDecimal.ZERO), 2, BigDecimal.ROUND_HALF_UP));
                    dataVO.setOperatingCashRatio(BigDecimalUtil.divide(map.getOrDefault(K57, BigDecimal.ZERO), map.getOrDefault(KLJ1, BigDecimal.ZERO), 2, BigDecimal.ROUND_HALF_UP, 100));
                    dataVO.setTotalInterestLiabilities(BigDecimalUtil.divide(map.getOrDefault(K33, BigDecimal.ZERO), unit, 2, BigDecimal.ROUND_HALF_UP));
                    dataVO.setTotalNetProfit(BigDecimalUtil.divide(map.getOrDefault(K58, BigDecimal.ZERO), unit, 2, BigDecimal.ROUND_HALF_UP));
                    dataVO.setTotalProfitTax(BigDecimalUtil.divide(BigDecimalUtil.add(map.getOrDefault(K58, BigDecimal.ZERO), map.getOrDefault(KSUM40, BigDecimal.ZERO)), unit, 2, BigDecimal.ROUND_HALF_UP));
                    return dataVO;
                })
                .orElse(new FinancialDataVO());
    }

    /**
     * code 转reportVO
     * @param valueCode
     * @param lastValueCode
     * @param budgetValueCode
     * @param codeName
     * @param codeValueMap
     * @return
     */
    public static IndicatorsReportVO getReportVO(String valueCode, String lastValueCode, String budgetValueCode, String codeName,
                                           Map<String, BigDecimal> codeValueMap){
        BigDecimal completeValue = codeValueMap.containsKey(valueCode) ?
                BigDecimalUtil.divide(codeValueMap.get(valueCode), BigDecimal.valueOf(10000), 2, BigDecimal.ROUND_HALF_UP) : new BigDecimal(0);
        BigDecimal lastValue = codeValueMap.containsKey(lastValueCode) ?
                BigDecimalUtil.divide(codeValueMap.get(lastValueCode), BigDecimal.valueOf(10000), 2, BigDecimal.ROUND_HALF_UP) : new BigDecimal(0);
        BigDecimal budgetValue = codeValueMap.containsKey(budgetValueCode) ?
                BigDecimalUtil.divide(codeValueMap.get(budgetValueCode), BigDecimal.valueOf(10000), 2, BigDecimal.ROUND_HALF_UP) : new BigDecimal(0);
        return valueToReportVO(completeValue, lastValue, budgetValue, valueCode, codeName);
    }

    public static IndicatorsReportVO valueToReportVO(BigDecimal completeValue, BigDecimal lastValue, BigDecimal budgetValue, String valueCode, String codeName){
        IndicatorsReportVO indicatorsReportVO = IndicatorsReportVO.builder()
                .value(completeValue)
                .lastValue(lastValue)
                .budgetValue(budgetValue)
                .code(valueCode)
                .codeName(codeName)
                .build();
        indicatorsReportVO.setGrowth(StringPool.DASH + StringPool.DASH);
        BigDecimal growth = BigDecimalUtil.divide(completeValue, lastValue, 4, BigDecimal.ROUND_HALF_UP, 100);

        if (completeValue != null && completeValue.compareTo(new BigDecimal(0)) != 0 && growth != null){
            if (lastValue. compareTo(new BigDecimal(0)) == -1){
                growth = BigDecimalUtil.subtract(new BigDecimal(100), growth);
            }else {
                growth = BigDecimalUtil.subtract(growth, new BigDecimal(100));
            }
            indicatorsReportVO.setGrowth(BigDecimalUtil.toShortString(growth, 2));
        }

        indicatorsReportVO.setCompletion(StringPool.DASH);
        BigDecimal completion = BigDecimalUtil.divide(completeValue, budgetValue, 4, BigDecimal.ROUND_HALF_UP, 100);
        if (completeValue != null && completeValue.compareTo(new BigDecimal(0)) == 1 && completion != null){
            indicatorsReportVO.setCompletion(BigDecimalUtil.toShortString(completion, 2));
        }
        return indicatorsReportVO;
    }

    /**
     * code 转reportVO
     * @param valueCode
     * @param valueCodes
     * @param lastValueCodes
     * @param budgetValueCodes
     * @param codeName
     * @param codeValueMap
     * @return
     */
    public static IndicatorsReportVO getReportVO(String valueCode, List<String> valueCodes, List<String> lastValueCodes, List<String> budgetValueCodes, String codeName,
                                           Map<String, BigDecimal> codeValueMap){
        BigDecimal completeValue = BigDecimalUtil.divide(getSumValue(valueCodes, codeValueMap), BigDecimal.valueOf(10000), 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal lastValue = BigDecimalUtil.divide(getSumValue(lastValueCodes, codeValueMap), BigDecimal.valueOf(10000), 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal budgetValue = BigDecimalUtil.divide(getSumValue(budgetValueCodes, codeValueMap), BigDecimal.valueOf(10000), 2, BigDecimal.ROUND_HALF_UP);
        return valueToReportVO(completeValue, lastValue, budgetValue, valueCode, codeName);
    }

    public static BigDecimal getSumValue(List<String> sumCodes, Map<String, BigDecimal> codeValueMap){
        if (CollectionUtil.isEmpty(sumCodes)){
            return null;
        }
        BigDecimal sumValue = new BigDecimal(0);
        for (String sumCode : sumCodes){
            if (codeValueMap.containsKey(sumCode)){
                sumValue = BigDecimalUtil.add(sumValue, codeValueMap.get(sumCode));
            }
        }
        return sumValue;
    }

}
